home *** CD-ROM | disk | FTP | other *** search
- (c) Copyright 1989 Commodore-Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice, and
- is provided "as is" without warranty of any kind, either express or implied.
- The entire risk as to the use of this information is assumed by the user.
-
-
-
- MIDI Output in Assembler
-
- by Darius Taghavy, CATS
-
-
- The Amiga's serial.device provides a software interface to the serial port
- which is suitable for a wide variety of purposes. However, high-performance
- applications such as MIDI drivers may require direct access to the Amiga
- hardware which controls the serial port. The program listed below shows how
- to send MIDI data over the serial port using direct access to the Amiga's
- Paula chip I/O registers.
-
- It is important to note that MIDI applications which use direct access to
- the serial port I/O registers must first gain exclusive access to the serial
- hardware by opening the misc.resource and allocating MR_SERIALBITS and
- MR_SERIALPORT. By doing this, the application becomes the "owner" of the
- serial port which prevents other tasks which may be running from interfering
- with serial I/O.
-
- The example program demonstrates direct access to the internal serial port
- through the Paula chip I/O registers and provides a very useful MIDI function:
- it turns off all notes. If you have ever used MIDI software, then you may
- be familiar with the stuck-note phenomenon. A stuck note is a note that
- sustains forever. Stuck notes happen because the duration of a note is
- determined by the elapsed time between a NOTE ON and a NOTE OFF event. If
- a NOTE OFF event ever gets lost you end up with a stuck note. The MIDI
- standard does provide an ALL NOTES OFF command, however, not all tone
- generators respond to it properly, and not all sequencers provide a way to
- send the command.
-
- The example program, named Panic, solves this problem by sending a NOTE ON
- command with a velocity of zero for all 128 notes on all 16 channels. In
- other words, each possible note is turned of individually forcing the
- sustaining culprit in your MIDI system to shut up.
-
- The Panic program is written in assembler to keep the code small and to save
- execution time. The program also employs the idea of a running status to
- save execution time by reducing the number of bytes it has to send. In
- accordance with the official MIDI specification, as long as data of the same
- status is being sent (i.e., NOTE ON) we can just keep sending the associated
- data bytes which, in this case, is 2 bytes for pitch and velocity,
- respectively. There is no need to re-transmit the status byte with every
- message.
-
- In the example code, this is implemented by cycling through the (inner)
- note_loop for 128 times, once for each MIDI note number. Since the MIDI
- channel information is imbedded in the lower nybble of the status byte, a
- new status byte must be sent when switching to a different channel. This is
- implemented as the (outer) channel_loop which loops 16 times, once for each
- MIDI channel. Using a running status cuts I/O activity by a third.
-
- Panic demonstrates assembler independent code by using the SECTION CODE
- and SECTION DATA directives. All Amiga assemblers will understand this. Panic
- also uses the statement, XDEF _panic, to make it callable from another module
- (say, a C main program). Manx users, please note that this is much better
- than using the Manx directive public since it is portable between assemblers
- (public is not). Use XREF for referencing external labels and XDEF for
- making labels available to external modules.
-
- Panic can be assembled and linked as is. No special assembler or linker flags
- are needed. The resulting executable is a mere 164 bytes long and only takes
- approximately 1.3 seconds to execute (using MANX 3.6a as and ln).
- The length of the transmitted MIDI data itself is 4112 bytes:
-
- (2 note/velocity bytes * 128 notes) + (1 status byte * 16 channels)
- = 4112 bytes.
-
- The MIDI transfer rate is defined as 31250 baud or about 3125 MIDI bytes/sec.
- This figure takes into account start and stop bits ( a MIDI byte is 10 bits ).
- Hence, time t for transmitting these events in an ideal world (ideal UART and
- crystal) is:
-
- total number of bytes 4112 bytes
- t = ---------------------------- = --------------------- = 1.31584 seconds.
- MIDI transfer rate 3125 bytes/sec
-
- Note that the Panic program assumes the serial baud rate is already set to
- 31250 baud and that the misc.resource has been allocated. As such there are
- two uses for this program.
-
- First, Panic could be used as a utility in conjunction with a sequencer that
- does not have a true all-notes-off feature or that lacks even the generic
- MIDI command \ff<Courier>ALL NOTES OFF\ff<Times>. In fact, I originally
- wrote Panic because no Amiga sequencer at the time offered this important
- feature.
-
- When Panic is used this way, it makes sense to not set the serial baud rate
- (your sequencer already took care of it) and to not allocate the serial port
- (the sequencer probably already has exclusive access to it).
-
- A second use for Panic would be to link it with your own code (say, a
- sequencer) which properly allocates the serial port and sets the baud rate.
- I encourage developers to include Panic in their code. In either case, it
- is important to make sure that other tasks have been locked out from using
- the serial port before hitting the serial port hardware registers directly.
-
- The program is listed on the next page.
-
-
- ;----------------------------------------------------------------
- ; PANIC (c)1990 by Darius Taghavy
- ;----------------------------------------------------------------
- ;sends note #0-127 with zero (0) velocity on all 16 MIDI channels
- ;MANX: as panic.asm; ln panic panic.o
- ;----------------------------------------------------------------
- ; this code assumes SERPER register to be set to MIDI baud rate
- ; it also assumes that we have exclusive access to the serial port
- ; hardware and related resources
-
-
- SECTION CODE
- XDEF _panic ;make available as 'C' function
-
- SECTION DATA
- CUSTOM_CHIPS equ $dff000 ;custom chips base address
- TBE equ 5 ;Transmitt Buffer Empty Bit
-
- ;Paula serial port register offsets from custom chip base address
- SERDAT equ $030 ;data output(WRITE ONLY)
- SERDATR equ $018 ;data/status(READ ONLY)
-
-
- SECTION CODE
- _panic move.l d2,-(a7) ;save d2
- lea CUSTOM_CHIPS,a0 ;load custom chip base
- move.w #15,d1 ;16 MIDI channels
- channel_loop move.w #127,d2 ;128 MIDI notes
-
- ;-------------status byte
- move.b d1,d0 ;get MIDI channel
- andi.b #$f,d0 ;nibble
- or.b #$90,d0 ;Note On Status
- andi.w #$ff,d0 ;clear high byte
- ori.w #$100,d0 ;set stop bit
-
- 1$ btst.b #TBE,SERDATR(a0) ;wait for free serialport
- beq 1$
-
- move.w d0,SERDAT(a0) ;send byte
-
- ;-------------note number
-
- note_loop move.b d2,d0 ;get note number
- andi.w #$ff,d0 ;clear high byte
- ori.w #$100,d0 ;set stop bit
-
- 2$ btst.b #TBE,SERDATR(a0) ;wait for free serialport
- beq 2$
- move.w d0,SERDAT(a0) ;send pitch byte
-
- ;------------velocity = 0
-
- 3$ btst.b #TBE,SERDATR(a0) ;wait for free serialport
- beq 3$
-
- move.w #$100,SERDAT(a0) ;send zero velocity
-
- dbra d2,note_loop ;loop 128 times
- dbra d1,channel_loop ;loop 16 times
- move.l (a7)+,d2 ;restore d2
- rts
-
- END
-